package org.pearl.springbootsecurity.demo.MP.data;

import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by TD on 2021/11/4
 * 获取MapperScan，并初始化包含DataScope注解的Mapper方法
 */
@Slf4j
public class ImportMapperScannerRegistrar implements ImportBeanDefinitionRegistrar {


    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 1.获取MapperScan注解上的配置
        AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
        List<String> basePackages = new ArrayList<>();
        if (annotationAttributes != null) {
            // 添加basePackages属性
            basePackages.addAll(
                    Arrays.stream(annotationAttributes.getStringArray("basePackages")).filter(StringUtils::hasText).collect(Collectors.toList()));
            // 添加value属性
            basePackages.addAll(
                    Arrays.stream(annotationAttributes.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
            // 添加MapperScan basePackageClasses属性
            basePackages.addAll(Arrays.stream(annotationAttributes.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName)
                    .collect(Collectors.toList()));
            // 如果没有配置扫描路径，添加默认路径
            if (basePackages.isEmpty()) {
                basePackages.add(getDefaultBasePackage(importingClassMetadata));
            }
        }
        // 2. 初始化扫描
        InMemoryDataScopeMetaStore.initCacheMap();
        ClassPathDataScopeScanner scanner = new ClassPathDataScopeScanner();
        for (String e : basePackages) {
            try {
                List<Class<?>> classes = scanner.doScan(e, Object.class);
                for (Class<?> aClass : classes) {
                    Method[] methods = aClass.getMethods();// 所有方法
                    // 2.1 反射获取方法上注解
                    for (Method method : methods) {
                        DataScope dataScope = method.getAnnotation(DataScope.class);
                        if (null != dataScope) {
                            DataScopeMapperProperty dataScopeProperty = new DataScopeMapperProperty(dataScope);
                            InMemoryDataScopeMetaStore.putCache(aClass.getName()+"."+method.getName(), dataScopeProperty);
                        }
                    }
                    // 2.2 查找类上注解
                    DataScope classAnnotation = aClass.getAnnotation(DataScope.class);
                    if (null != classAnnotation) {
                        InMemoryDataScopeMetaStore.putCache(aClass.getName(), new DataScopeMapperProperty(classAnnotation));
                    }
                }
            } catch (Exception ex) {
                log.error("Scan failed {}" + ex.getMessage());
                ex.printStackTrace();
            }
        }
    }

    private static String getDefaultBasePackage(AnnotationMetadata importingClassMetadata) {
        return ClassUtils.getPackageName(importingClassMetadata.getClassName());
    }

}
